#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "sqlite3.h"
#include "circlebuff.h"
#include "public.h"
#include "cJSON.h"

char *getJson(int idx);
int pAlmOidIdx[500];
int *pReadOidIdx;
INT32U g_reportTimeCnt = 0;
long g_currentSecondTime;
char g_currentTime[50] = {0};
static char sMqNewpacketFlag = 0;
static char tmp[50] = {0};
char str[1500] = {0};
void formJsonPacket(int idx);
MBSETLIST g_mbSetPakcetList[6];
static void IO_DI_DataTreat(void);
static void IO_DO_DataTreat(void);
static void MB_read_DataTreat(void);
static void MB_set_DataTreat(void);
static void dataTreatInit(void);
static void MB_linkage_DataTreat(void);
static void linkageRuleClose_actOidValueRegain(void);
static void linkageRule_Type1_OidTrigger(int idx);
static void linkageRule_Type0_PeriodAutoAction(int idx);
void data_classification(void)
{
	int m = 0;
	int i;

	for (i = 0; i < g_tabLen; i++)
	{
		if (g_devDataTab[i].dataOption == ALM_20)
			m++;
	}
	//pAlmOidIdx= (int *)malloc(m+1);
	m = 0;
	for (i = 0; i < g_tabLen; i++)
	{
		if (g_devDataTab[i].dataOption == ALM_20)
		{
			pAlmOidIdx[m++] = i;
		}
	}
	pAlmOidIdx[m] = 0xffff;
}

void dataReport_treat(void)
{
	int i;

	getTimeString(&g_currentTime[0]);
	for (i = 0; i < g_tabLen; i++)
	{
		if (g_devDataTab[i].upSentPeriod == 0)
			continue;
		if ((g_reportTimeCnt % g_devDataTab[i].upSentPeriod) != 0)
			continue;
		if (g_devDataTab[i].belongToOid > 10)
			continue;
		formJsonPacket(i);
	}
}
void formJsonPacket(int idx)
{
	char *s = getJson(idx);

	strcpy(str, s);
	free(s);
	pthread_mutex_lock(&comBuff0.lock);
	if (strlen(str) > 0)
	{
		AP_circleBuff_WritePacket((INT8U *)str, (INT16U)strlen(str), DTU2MQTPA);
	}
	pthread_mutex_unlock(&comBuff0.lock);
}

void dataInt2String(void)
{
	double dValue;
	int i;
	for (i = 0; i < g_tabLen; i++)
	{
		dValue = (double)g_devDataTab[i].valueInt / g_devDataTab[i].radio;
		gcvt(dValue, 8, g_devDataTab[i].valueString);
		//	printf("g_devDataTab[i].valueString=%s\n",g_devDataTab[i].valueString);
	}
}
void data4Test(void)
{
	int i;
	for (i = 0; i < g_tabLen; i++)
	{
		if (g_devDataTab[i].dataOption != ALM_20 && g_devDataTab[i].dataOption != SET_1)
			g_devDataTab[i].valueInt = i;
	}
}
char *getJson(int idx)
{
	int m;

	cJSON *jsonRoot = NULL;
	cJSON *js_data = NULL;
	char *p = NULL;
	jsonRoot = cJSON_CreateObject();
	if (jsonRoot == NULL)
		goto end;
	cJSON_AddStringToObject(jsonRoot, "version", g_mqComVer);
	cJSON_AddStringToObject(jsonRoot, "type", g_devDataTab[idx].ssType);
	strcat(tmp, g_mqComId);
	strcat(tmp, g_devDataTab[idx].ssDevId);
	cJSON_AddStringToObject(jsonRoot, "id", tmp);
	tmp[0] = 0;
	cJSON_AddStringToObject(jsonRoot, "time", g_currentTime);
	cJSON_AddItemToObject(jsonRoot, "data", js_data = cJSON_CreateObject());
	if (g_devDataTab[idx].belongToOid != 1)
	{
		cJSON_AddStringToObject(js_data, g_devDataTab[idx].ssDataType, g_devDataTab[idx].valueString);
	}
	else
	{
		cJSON_AddStringToObject(js_data, g_devDataTab[idx].ssDataType, g_devDataTab[idx].valueString);
		for (m = 0; m < g_tabLen; m++)
		{
			if (g_devDataTab[m].upSentPeriod == 0)
				continue;
			if (g_devDataTab[idx].oid == g_devDataTab[m].belongToOid)
			{
				cJSON_AddStringToObject(js_data, g_devDataTab[m].ssDataType, g_devDataTab[m].valueString);
			}
		}
	}
	p = cJSON_PrintUnformatted(jsonRoot);

end:
	cJSON_Delete(jsonRoot);
	return p;
}
void relayTest(void)
{
	static char temp = 0;
	static char i = 0;

	return;
	temp = 1 << i;
	if (i++ > 7)
		i = 0;
	printf("relayTest temp=%x\n", temp);
	mcuMonitorObjVal[1].serVal[0] = temp;
	int j;
	for (j = 0; j < IO_DO_MAXLEN; j++)
	{
		g_IOoutput[j].value = i % 2;
	}
}
void test(void)
{
	int tempVal;
	get_jxOidValue(501, (INT8U *)&tempVal);
	printf("501tempVal=%x\n", tempVal);
	get_jxOidValue(502, (INT8U *)&tempVal);
	printf("502tempVal=%x\n", tempVal);

	get_jxOidValue(111, (INT8U *)&tempVal);
	printf("111tempVal=%x\n", tempVal);
}
void *DataTreatThread(void)
{
	//	data_classification();
	dataTreatInit();
	while (1)
	{
		//usleep(200000);
		sleep(2);
		g_currentSecondTime = time(NULL);
		IO_DI_DataTreat();
		IO_DO_DataTreat();
		MB_read_DataTreat();
		MB_set_DataTreat();
		MB_linkage_DataTreat();
		//test();
		//data4Test();
		//dataInt2String();
		//dataReport_treat();
		//relayTest();
	}
}
static void IO_DI_DataTreat(void)
{
	int i = search_nativeMcuTab_idx(IO_DI_OID);
	if (i == 0xffff)
		return;
	int temp, tempVal;
	memcpy(&temp, &mcuMonitorObjVal[i].devVal[0], 4);
	for (i = 0; i < IO_DI_MAXLEN; i++)
	{
		if (g_IOinput[i].oid == 0)
			continue;
		if ((temp & 1 << i) == 0)
		{
			if (g_IOinput[i].option == 0)
				tempVal = 0;
			else
				tempVal = 1;
		}
		else
		{
			if (g_IOinput[i].option == 0)
				tempVal = 1;
			else
				tempVal = 0;
		}
		set_jxOidValue(g_IOinput[i].oid, (INT8U *)&tempVal);
		// printf("tempVal=%d\n",tempVal);
		// int test;
		// get_jxOidValue(g_IOinput[i].oid,&test);
		// printf("test=%d\n",test);
	}
}
static void IO_DO_DataTreat(void)
{

	int i, temp, tempVal;

	for (i = 0; i < IO_DO_MAXLEN; i++)
	{
		if (g_IOoutput[i].oid == 0)
			continue;
		if (!get_jxOidValue(g_IOoutput[i].oid, (INT8U *)&temp))
			continue;
		temp &= 1;
		if (temp ^ g_IOoutput[i].option)
		{
			g_IOoutput[i].value = 1;
		}
		else
		{
			g_IOoutput[i].value = 0;
		}
		//printf("g_IOoutput[i].oid=%d;g_IOoutput[i].value=%d\n",g_IOoutput[i].oid,g_IOoutput[i].value);
	}
}
static void MB_read_DataTreat(void)
{
	int i;

	for (i = 0; i < g_mbPollTabLen; i++)
	{
		if (g_mbPollTab[i].oid == 0 || g_mbPollTab[i].rwFlag != 0)
			continue;

		if (g_mbPollTab[i].len <= 2)
		{
			set_jxOidValue(g_mbPollTab[i].oid, (INT8U *)&g_mbPollTab[i].devValue);
		}
		else
		{
			int idx = g_mbPollTab[i].mbLongDataAtListStartAddr;
			set_jxOidValue(g_mbPollTab[i].oid, (INT8U *)&g_mbLongDataList[idx]);
		}
	}
}
static void MB_set_DataTreat(void)
{
	int i, j;
	static char nextStartIdx = 0;
	static char nextIdx = 0;

	if (nextStartIdx >= g_mbPollTabLen)
		nextStartIdx = 0;

	for (i = nextStartIdx; i < g_mbPollTabLen; i++)
	{
		nextStartIdx++;

		if (g_mbPollTab[i].oid == 0 || g_mbPollTab[i].rwFlag == 0)
			continue;
		int idx = g_mbPollTab[i].pollPortNameIdx;
		if (idx >= 6)
			continue;
		if (g_mbSetPakcetList[idx].status != SET_IDLE)
			continue;
		if (g_mbPollTab[i].adjustFlag == 0)
		{
			get_jxOidValue(g_mbPollTab[i].oid, (INT8U *)&g_mbPollTab[i].serValue);
		}
		else
		{
			lWord4Byte temp;
			get_jxOidValue(g_mbPollTab[i].oid, (INT8U *)&temp.byte[0]);
			temp.lword = (temp.lword - g_mbPollTab[i].addSubValue) * g_mbPollTab[i].devideValue / g_mbPollTab[i].multiValue;
			memcpy(&g_mbPollTab[i].serValue[0], &temp.byte[0], 2);
		}
		// printf("\n---mobus setdata treat---\n ");
		// printf("g_mbPollTab[i].oid=%d ", g_mbPollTab[i].oid);
		// printf("g_mbPollTab[i].serValue[0]=%x ", g_mbPollTab[i].serValue[0]);
		// printf("g_mbPollTab[i].serValue[1]=%x ", g_mbPollTab[i].serValue[1]);
		// printf("g_mbPollTab[i].devValue[0]=%x ", g_mbPollTab[i].devValue[0]);
		// printf("g_mbPollTab[i].devValue[1]=%x ", g_mbPollTab[i].devValue[1]);
		if (g_mbPollTab[i].len > 2)
			continue;
		int rc = memcmp(&g_mbPollTab[i].serValue, &g_mbPollTab[i].devValue, g_mbPollTab[i].len);

		if (rc != 0)
		{
			g_mbSetPakcetList[idx].status = SET_SENDING;
			g_mbSetPakcetList[idx].oid = g_mbPollTab[i].oid;
			g_mbSetPakcetList[idx].sendLen = 8;
			g_mbSetPakcetList[idx].recvLen = 8;

			g_mbSetPakcetList[idx].ctx[0] = g_mbPollTab[i].mbDevAddr;
			g_mbSetPakcetList[idx].ctx[2] = g_mbPollTab[i].mbStartAddr >> 8;
			g_mbSetPakcetList[idx].ctx[3] = g_mbPollTab[i].mbStartAddr;
			if (g_mbPollTab[i].len == 1 && g_mbPollTab[i].stdMbSetCmd == 0x05)
			{
				g_mbSetPakcetList[idx].cmd = 0x05;
				g_mbSetPakcetList[idx].ctx[1] = 0x05;
				if (0 != g_mbPollTab[i].serValue[0])
				{
					g_mbSetPakcetList[idx].ctx[4] = 0XFF;
					g_mbSetPakcetList[idx].ctx[5] = 0X00;
				}
				else
				{
					g_mbSetPakcetList[idx].ctx[4] = 0X00;
					g_mbSetPakcetList[idx].ctx[5] = 0X00;
				}
			}
			else if (g_mbPollTab[i].len == 2 && g_mbPollTab[i].stdMbSetCmd == 0x06)
			{
				g_mbSetPakcetList[idx].cmd = 0x06;
				g_mbSetPakcetList[idx].ctx[1] = 0x06;
				g_mbSetPakcetList[idx].ctx[4] = g_mbPollTab[i].serValue[1];
				g_mbSetPakcetList[idx].ctx[5] = g_mbPollTab[i].serValue[0];
			}
			else
			{
				g_mbSetPakcetList[idx].status = SET_IDLE;
			}
			int temp = modbusCrc16((INT8U *)&g_mbSetPakcetList[idx].ctx, 6);
			g_mbSetPakcetList[idx].ctx[6] = temp >> 8;
			g_mbSetPakcetList[idx].ctx[7] = temp;
		}
	}
	// printf("\n----------------------------------------\n");
	// for (i = 0; i < 6; i++)
	// {
	// 	printf("sendlen=%d ", g_mbSetPakcetList[i].sendLen);
	// 	printf("recvLen=%d ", g_mbSetPakcetList[i].recvLen);
	// 	printf("status=%d ", g_mbSetPakcetList[i].status);
	// 	printf("oid=%d ", g_mbSetPakcetList[i].oid);
	// 	printf("ctx=");
	// 	for (j = 0; j < 8; j++)
	// 	{
	// 		printf("%x ", g_mbSetPakcetList[i].ctx[j]);
	// 	}
	// 	printf("\n");
	// }
	// printf("\n----------------------------------------\n");
}
static void linkageRule_Type0_PeriodAutoAction(int idx)
{
	struct tm *ptm;
	int i;
	long ts;

	i = idx;
	if (g_jxLinkageTab[i].curTime > g_currentSecondTime || g_currentSecondTime > g_jxLinkageTab[i].curTime + 10)
	{
		g_jxLinkageTab[i].status = IDLE;
		g_jxLinkageTab[i].startActionTime = 0;
		g_jxLinkageTab[i].curTime = g_currentSecondTime;
		g_jxLinkageTab[i].value ^= ~g_jxLinkageTab[i].actBitMask;
		return;
	}
	g_jxLinkageTab[i].curTime = g_currentSecondTime;
	ts = g_currentSecondTime;
	ptm = localtime(&ts);

	int curSecondTimeInToday = ptm->tm_hour * 3600 + ptm->tm_min * 60 + ptm->tm_sec;

	if (g_jxLinkageTab[i].status == IDLE)
	{
		if (curSecondTimeInToday >= g_jxLinkageTab[i].linkageStartTime && curSecondTimeInToday < g_jxLinkageTab[i].linkageStartTime + g_jxLinkageTab[i].linkageKeepTime)
		{
			g_jxLinkageTab[i].startActionTime = g_jxLinkageTab[i].curTime;
			g_jxLinkageTab[i].status = WORKING;
			g_jxLinkageTab[i].value |= g_jxLinkageTab[i].actBitMask;
		}
	}
	else if (g_jxLinkageTab[i].status == WORKING)
	{
		if (g_jxLinkageTab[i].curTime - g_jxLinkageTab[i].startActionTime > g_jxLinkageTab[i].linkageKeepTime)
		{
			g_jxLinkageTab[i].value ^= ~g_jxLinkageTab[i].actBitMask;
			g_jxLinkageTab[i].status = WAITING;
		}
	}
	else if (g_jxLinkageTab[i].status == WAITING)
	{
		if (g_jxLinkageTab[i].curTime - g_jxLinkageTab[i].startActionTime >= g_jxLinkageTab[i].linkageLoopPeriod)
		{
			g_jxLinkageTab[i].status = IDLE;
		}
	}
	else
	{
		g_jxLinkageTab[i].status = IDLE;
		g_jxLinkageTab[i].value ^= ~g_jxLinkageTab[i].actBitMask;
	}
}
static void linkageRule_Type1_OidTrigger(int idx)
{
	struct tm *ptm;
	int i;

	i = idx;
	int TriggerDeviceStatusValue = 0;
	get_jxOidValue(g_jxLinkageTab[i].oid_triggerDevice, (INT8U *)&TriggerDeviceStatusValue);

	if (g_jxLinkageTab[i].linkageKeepTime > 0)
	{
		if (g_jxLinkageTab[i].curTime > g_currentSecondTime || g_currentSecondTime > g_jxLinkageTab[i].curTime + 10)
		{
			g_jxLinkageTab[i].status = IDLE;
			g_jxLinkageTab[i].startActionTime = 0;
			g_jxLinkageTab[i].curTime = g_currentSecondTime;
			g_jxLinkageTab[i].value ^= ~g_jxLinkageTab[i].actBitMask;
			return;
		}
		g_jxLinkageTab[i].curTime = g_currentSecondTime;
		if (g_jxLinkageTab[i].status == IDLE)
		{
			if (TriggerDeviceStatusValue != 0)
			{
				g_jxLinkageTab[i].value |= g_jxLinkageTab[i].actBitMask;
				g_jxLinkageTab[i].status = WORKING;
				g_jxLinkageTab[i].startActionTime = g_jxLinkageTab[i].curTime;
			}
		}
		else if (g_jxLinkageTab[i].status == WORKING)
		{
			if (g_jxLinkageTab[i].curTime - g_jxLinkageTab[i].startActionTime > g_jxLinkageTab[i].linkageKeepTime)
			{
				g_jxLinkageTab[i].value ^= ~g_jxLinkageTab[i].actBitMask;
				g_jxLinkageTab[i].status = WAITING;
			}
		}
		else if (g_jxLinkageTab[i].status == WAITING)
		{
			if (TriggerDeviceStatusValue == 0)
			{
				g_jxLinkageTab[i].status = IDLE;
			}
		}
		else
		{
			g_jxLinkageTab[i].status = IDLE;
		}
	}
	else
	{
		if (TriggerDeviceStatusValue == 0)
		{
			g_jxLinkageTab[i].value ^= ~g_jxLinkageTab[i].actBitMask;
		}
		else
		{
			g_jxLinkageTab[i].value |= g_jxLinkageTab[i].actBitMask;
		}
	}
}
static void MB_linkage_DataTreat(void)
{
	int i;

	if(g_linkageControl.value==0)
	{
		if(g_linkageControl.writeFlag)
		{
			linkageRuleClose_actOidValueRegain();
			g_linkageControl.writeFlag=0;
		}
		return;
	}
	for (i = 0; i < g_jxLinkageTabLen; i++)
	{
		if (g_jxLinkageTab[i].linkageType == 0)
		{
			linkageRule_Type0_PeriodAutoAction(i);
		}
		else if (g_jxLinkageTab[i].linkageType == 1)
		{
			linkageRule_Type1_OidTrigger(i);
		}
		else
		{
		}
	}
	int temp = g_jxLinkageTab[0].value;
	for (i = 1; i < g_jxLinkageTabLen; i++)
	{
		if (g_jxLinkageTab[i - 1].oid_actDevice != g_jxLinkageTab[i].oid_actDevice)
		{
			temp = (temp != 0) ? 1 : 0;
			set_jxOidValue(g_jxLinkageTab[i - 1].oid_actDevice, (INT8U *)&temp);
			temp = g_jxLinkageTab[i].value;
			if (i == g_jxLinkageTabLen - 1)
			{
				temp = (temp != 0) ? 1 : 0;
				set_jxOidValue(g_jxLinkageTab[i].oid_actDevice, (INT8U *)&temp);
			}
		}
		else
		{
			temp |= g_jxLinkageTab[i].value;
			if (i == g_jxLinkageTabLen - 1)
			{
				temp = (temp != 0) ? 1 : 0;
				set_jxOidValue(g_jxLinkageTab[i].oid_actDevice, (INT8U *)&temp);
			}
		}
	}
}
static void linkageRuleClose_actOidValueRegain(void)
{
	int i;

	for (i = 0; i < g_jxLinkageTabLen; i++)
	{
		int idx=get_jxOidIdx(g_jxLinkageTab[i].oid_actDevice);
		if (idx>=0)
		{
			g_jxDevDataTab[i].devValInt=g_jxDevDataTab[i].sqlValue; 
		}
	}
}
static void dataTreatInit(void)
{
	int i, j;
	for (i = 0; i < 6; i++)
	{
		//g_mbSetPakcetList[i].portIdx = i;
		g_mbSetPakcetList[i].sendLen = 0xff;
		g_mbSetPakcetList[i].recvLen = 0xff;
		g_mbSetPakcetList[i].status = SET_IDLE;

		for (j = 0; j < 8; j++)
		{
			g_mbSetPakcetList[i].ctx[j] = 0xff;
		}
	}
}
